#include "Level.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

static unsigned int LINE_NUMBER = 1;

void Level_print (Level * lvl)
{

	Uchar	x, y;

	printf ("Level information\n\n");
	printf ("Default pin size: %d\n", lvl->pinsize);
	printf ("Default speed: %.1f\n",  lvl->speed);
	printf ("Default edgesize: %d\n", lvl->edgesize);

	if ( lvl->timer > 0 )
		printf ("Timer set to %u seconds\n", lvl->timer);
	else
		printf ("No timer set\n");

	printf ("Brick data {\n");

	for ( y = 0; y < 8; y++)
	{
		if ( y != 0 ) printf ("\n");
		for ( x = 0; x < 16; x++ )
		{
			if ( x != 0 ) printf (" ");
			printf ("%c", lvl->bricks[x][y]);
		}
	}

	printf ("\n}\n");
}

void eatup_comments_and_empty_lines (FILE * fp)
{
	char line[255];
	char car;
	
	for ( ; ; )
	{

		car = fgetc(fp);

		if ( (car != NEWLINE) && (car != COMMENT_TOKEN) )
			break;

		/* Skip line */
		while ( car != NEWLINE )
			car = fgetc(fp);
		
		/* Finished reading the line */
		LINE_NUMBER ++;

	}
		
	/* Put back the last character in the stream */
	ungetc (car, fp);
		
}

void get_keyword (FILE * fp, char * keyword)
{

	char car;
	char *read;

	read = keyword;

	for ( ; ; )
	{
	
		car = fgetc(fp);

		if ( (car == SEPARATOR) || (car == NEWLINE) )
			break;

		*read = car;
		read ++;

	}

	/* Put back the last character in the stream */
	ungetc (car, fp);	

	/* Finish the character string */
	*read = '\0';
}

void get_value (FILE * fp, char * value)
{

	char car;
	char *read;

	read = value;

	for ( ; ; )
	{
	
		car = fgetc(fp);

		if ( car == NEWLINE )
			break;
		
		*read = car;
		read ++;

	}

	/* Put back the last character in the stream */
	ungetc (car, fp);	

	/* Finish the character string */
	*read = '\0';
}

void parse_options (Level * lvl, FILE * fp)
{
	
	char car;
	char keyword[16], value[8];

	for ( ; ; )
	{

		eatup_comments_and_empty_lines (fp);
		get_keyword (fp, &keyword[0]);

		/* Search for the separator */
		if ( (car = fgetc(fp)) != SEPARATOR )
		{
			fprintf (stderr,
				"Missing separator '%c' at line %d: %c\n",
				SEPARATOR, LINE_NUMBER, car);
			exit (-1);
		}

		/* If we begin the bricks section, finish parsing
		   the options and start reading the level data.
		   */
		if ( !strcmp(keyword, KEYWORD_BRICKS) )
		{

			/* Skip the newline */
			car = fgetc(fp);
			LINE_NUMBER ++;
			break;
		}
		/* Then, a value */
		get_value (fp, &value[0]);

		if ( !strcmp(keyword, KEYWORD_PINSIZE) )
		{

			int pinsize;

			pinsize = atoi(&value[0]);
			if ( (pinsize < MIN_PINSIZE) ||
			     (pinsize > MAX_PINSIZE) )
			{
			fprintf (stdout,
			"Warning at line %d: specified value for 'pinsize': %d out"
			" of the advised values [%d,%d]\n", LINE_NUMBER,
			pinsize, MIN_PINSIZE, MAX_PINSIZE);
			}
			
			lvl->pinsize = pinsize;

		}
		else if ( !strcmp(keyword, KEYWORD_SPEED) )
		{

			float speed;

			speed = atof(&value[0]);
			if ( (speed < MIN_SPEED) ||
			     (speed > MAX_SPEED) )
			{
			fprintf (stdout,
			"Warning at line %d: specified value for 'speed': %.1f out"
			" of the advised values [%.1f,%.1f]\n", LINE_NUMBER,
			speed, MIN_SPEED, MAX_SPEED);
			}
			
			lvl->speed = speed;

		}
		else if ( !strcmp(keyword, KEYWORD_EDGESIZE) )
		{

			int edgesize;

			edgesize = atoi(&value[0]);
			if ( (edgesize < MIN_EDGESIZE) ||
			     (edgesize > MAX_EDGESIZE) )
			{
			fprintf (stderr,
			"Error at line %d: specified value for 'edgesize': %d out"
			" of the advised values [%d,%d]\n", LINE_NUMBER,
			edgesize, MIN_EDGESIZE, MAX_EDGESIZE);
			exit (-1);
			}
			
			lvl->edgesize = edgesize;

		}
		else if ( !strcmp(keyword, KEYWORD_TIMER) )
		{

			Uint32 timer;

			timer = atol(&value[0]);
			
			if ( timer == 0 )
			{
			fprintf (stdout,
			"Warning at line %d: special value zero for timer "
			"is used to desactivate the timer.\n"
			"It is the default value so I advise you not"
			" to specify any timer for this level.", LINE_NUMBER);
			}
			else if ( (timer < MIN_TIMER) ||
			     	  (timer > MAX_TIMER) )
			{
			fprintf (stdout,
			"Warning at line %d: specified value for 'timer': %d out"
			" of the advised values [%d,%d]\n", LINE_NUMBER,
			timer, MIN_TIMER, MAX_TIMER);
			}
			
			lvl->timer = timer;

		}
		else {
		fprintf (stderr,
		"Syntax error at line %d: Keyword '%s' not supported.\n",
		LINE_NUMBER, keyword);
		exit (-1);
		}
	
		/* Eatup end of line */
		fgetc(fp);
		LINE_NUMBER ++;

	}

}

void check_brickcode (char code)
{

	switch (code)
	{
		case '0': break;
		case '1': break;
		case '2': break;
		case '3': break;
		case 'x': break;
		
		default:
		fprintf (stderr,
		"Syntax error line %d: bad brick code: '%c'\n",
		LINE_NUMBER, code);
		exit (-1);
		break;
	}

}

void Level_import (Level * lvl, const char * filename)
{

	FILE * fp;
	Uchar  x, y;
	char   car;
	Uchar  val;
	int    ret;
	char   keyword[32], value[8];

	fp = fopen (filename, "r");

	if ( fp == NULL )
	{
		fprintf (stderr,
		"Cannot import the level file: %s "
		" (errno = %d)\n", filename, errno);
		exit (-1);		
	}

	/* ******************** */
	/* Setup default values */
	/* ******************** */
	lvl->pinsize = DEFAULT_PINSIZE;
	lvl->speed   = DEFAULT_SPEED;
	lvl->edgesize= DEFAULT_EDGESIZE;
	lvl->timer   = DEFAULT_TIMER;

	/* ************* */
	/* Parse options */
	/* ************* */
	parse_options (lvl, fp);

	lvl->nhits   = 0;

	for ( y = 0; y < 8; y++ )
	{
		for ( x = 0; x < 16; x ++ )
		{

			val = fgetc (fp);

			/* Verify that the brick code is valid */
			check_brickcode(val);

			/*{*/
			/*val
			if ( car != 'a' )
				val = car - '0';
			else
				val = 0xa;*/
			/*}*/
	
			lvl->bricks[x][y] = val;

			if ( val > '0' && val < '4' )
				lvl->nhits += val - '0';

		}	

		/* Read new line */	
		fgetc(fp);

/*		ret = fscanf (fp, NEWLINE);		*/
		LINE_NUMBER++;

	}

	fclose (fp);

}

/*int main (int argc, char ** argv)
{

	Level set;

	if ( argc < 2 )
	{
		fprintf (stderr, "Filename expected.\n");
		exit (-1);
	}

	Level_import (&set, argv[1]);

	printf ("\n");
	Level_print  (&set);
	printf ("\n");

	exit (0);	

}*/

